import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.undo.UndoManager;
import java.awt.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class LexicalAnalysisPage {
    JPanel PagePanel;
    //打开的代码文件
    private File file;
    JFileChooser chooser;
    //文本区域组件
    private JTextArea textArea;
    //右上面板的文本域
    private JTextArea tokenTextArea;
    //右下面板的错误信息文本域
    private JTextArea errorTextArea;
    // 保存Token序列菜单项
    private JMenuItem fileMenu_saveToken;
    private JButton button_saveToken;
    private JMenuItem fileMenu_save;
    private JButton button_save;
    JMenuBar menuBar;


    public LexicalAnalysisPage() {
        PagePanel = new JPanel();
        PagePanel.setLayout(null);
        PagePanel.setBounds(0,0,1280,720);

        //初始化UI
        this.createUIComponents();
        //初始化文件选择器
        chooser = new JFileChooser();
    }
    public JPanel SwitchLexicalAnalysis(){
        return this.PagePanel;
    }
    public JMenuBar GetLexicalAnalysisMenuBar(){
        return this.menuBar;
    }
    private void createUIComponents() {
        menuBar = new JMenuBar();
        // 设置菜单栏字体
        Font menuFont = new Font("Microsoft YaHei", Font.PLAIN, 16);
        menuBar.setFont(menuFont);

        //文件菜单、打开，保存。
        JMenu fileMenu = new JMenu("文件");
        fileMenu.setFont(menuFont); // 设置字体
        menuBar.add(fileMenu);
        JMenuItem fileMenu_open = new JMenuItem("打开");
        fileMenu_open.setFont(menuFont); // 设置字体
        fileMenu.add(fileMenu_open);
        fileMenu_save = new JMenuItem("保存代码文件");
        fileMenu_save.setFont(menuFont); // 设置字体
        fileMenu_save.setEnabled(false);
        fileMenu.add(fileMenu_save);
        fileMenu_saveToken = new JMenuItem("保存Token序列");
        fileMenu_saveToken.setFont(menuFont); // 设置字体
        fileMenu_saveToken.setEnabled(false); // 初始时禁用保存Token序列功能
        fileMenu.add(fileMenu_saveToken);
        // 添加关闭菜单项
        JMenuItem fileMenu_close = new JMenuItem("关闭");
        fileMenu_close.setFont(menuFont); // 设置字体
        fileMenu.add(fileMenu_close);
        // 添加编辑菜单
        JMenu editMenu = new JMenu("编辑");
        editMenu.setFont(menuFont); // 设置字体
        menuBar.add(editMenu);
        JMenuItem editMenu_cut = new JMenuItem("剪切");
        editMenu_cut.setFont(menuFont); // 设置字体
        editMenu.add(editMenu_cut);
        JMenuItem editMenu_copy = new JMenuItem("复制");
        editMenu_copy.setFont(menuFont); // 设置字体
        editMenu.add(editMenu_copy);
        JMenuItem editMenu_paste = new JMenuItem("粘贴");
        editMenu_paste.setFont(menuFont); // 设置字体
        editMenu.add(editMenu_paste);
        editMenu.addSeparator();
        JMenuItem editMenu_undo = new JMenuItem("撤销");
        editMenu_undo.setFont(menuFont); // 设置字体
        editMenu.add(editMenu_undo);
        JMenuItem editMenu_redo = new JMenuItem("重做");
        editMenu_redo.setFont(menuFont); // 设置字体
        editMenu.add(editMenu_redo);
        // 功能菜单
        JMenu functionMenu = new JMenu("执行功能");
        functionMenu.setFont(menuFont); // 设置字体
        menuBar.add(functionMenu);
        JMenuItem functionMenu_analyze = new JMenuItem("词法分析");
        functionMenu_analyze.setFont(menuFont); // 设置字体
        functionMenu.add(functionMenu_analyze);

        //左面板
        JPanel leftPanel = new JPanel();
        leftPanel.setLayout(null);
        leftPanel.setBounds(150,20,520,600);
        leftPanel.setBorder(new LineBorder(Color.BLUE,2));
        PagePanel.add(leftPanel);
        //左面板上文本打开提示
        JLabel label1 = new JLabel("请选择要打开的文件");
        label1.setBounds(10,10,200,30);
        leftPanel.add(label1);

        //右上的token词法面板
        JPanel rightPanel = new JPanel();
        rightPanel.setLayout(null);
        rightPanel.setBounds(700,20,500,400);
        rightPanel.setBorder(new LineBorder(Color.GREEN,2));
        PagePanel.add(rightPanel);
        JLabel label2 = new JLabel("词法分析结果:Token序列");
        label2.setBounds(10,10,200,30);
        rightPanel.add(label2);

        //右下词法错误矿
        JPanel errorPanel = new JPanel();
        errorPanel.setLayout(null);
        errorPanel.setBounds(700,450,500,200);
        errorPanel.setBorder(new LineBorder(Color.ORANGE,2));
        PagePanel.add(errorPanel);

        //添加错误信息标签
        JLabel errorLabel = new JLabel("分析错误信息与分析结果");
        errorLabel.setBounds(10, 10, 200, 30);
        errorPanel.add(errorLabel);

        //添加不可编辑的错误信息文本域和滚动条到右下面板
        errorTextArea = new JTextArea();
        errorTextArea.setEditable(false);
        JScrollPane errorScrollPane = new JScrollPane(errorTextArea);
        errorScrollPane.setBounds(5, 45, 490, 150);
        errorScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        errorPanel.add(errorScrollPane);

        //添加左下角文本框
        textArea = new JTextArea();
        textArea.setEditable(true);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.setBounds(0,50,520,550);
        JScrollPane scrollPane = new JScrollPane(textArea);
        scrollPane.setBounds(5, 50, 510, 540);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        leftPanel.add(scrollPane);

        // 添加不可编辑的文本域和滚动条到右上面板
        tokenTextArea = new JTextArea();
        tokenTextArea.setEditable(false);
        JScrollPane tokenScrollPane = new JScrollPane(tokenTextArea);
        tokenScrollPane.setBounds(5, 35, 490, 360);
        tokenScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        rightPanel.add(tokenScrollPane);

        //快捷功能按钮 最左侧的按钮面板
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(null);
        buttonPanel.setBounds(10,20,130,600);
        buttonPanel.setBorder(new LineBorder(Color.GRAY,2));
        PagePanel.add(buttonPanel);
        JLabel label3 = new JLabel("快捷功能");
        label3.setBounds(10,10,100,30);
        buttonPanel.add(label3);
        JButton button_open = new JButton("打开文件");
        button_open.setBounds(10,40,100,60);
        buttonPanel.add(button_open);
        button_save = new JButton("保存文件");
        button_save.setBounds(10,110,100,60);
        buttonPanel.add(button_save);
        button_save.setEnabled(false);
        JButton button_close = new JButton("关闭文件");
        button_close.setBounds(10,180,100,60);
        buttonPanel.add(button_close);
        JLabel label4 = new JLabel("源代码词法分析功能");
        label4.setBounds(10,260,200,30);
        buttonPanel.add(label4);
        JButton button_analyze = new JButton("词法分析");
        button_analyze.setBounds(10,290,100,60);
        buttonPanel.add(button_analyze);
        button_saveToken = new JButton("保存结果");
        button_saveToken.setBounds(10,360,100,60);
        buttonPanel.add(button_saveToken);
        button_saveToken.setEnabled(false);
        //以下是组件事件
        fileMenu_open.addActionListener(e -> file_OpenAndSave("open", label1));
        button_open.addActionListener(e -> file_OpenAndSave("open", label1));
        fileMenu_save.addActionListener(e -> file_OpenAndSave("save", label1));
        button_save.addActionListener(e -> file_OpenAndSave("save", label1));
        fileMenu_saveToken.addActionListener(e -> saveTokenSequence());
        button_saveToken.addActionListener(e -> saveTokenSequence());
        fileMenu_close.addActionListener(e -> closeFile());
        button_close.addActionListener(e -> closeFile());
        //词法分析功能
        functionMenu_analyze.addActionListener(e -> performLexicalAnalysis());
        button_analyze.addActionListener(e -> performLexicalAnalysis());
        // 剪切功能
        editMenu_cut.addActionListener(e -> textArea.cut());
        // 复制功能
        editMenu_copy.addActionListener(e -> textArea.copy());
        // 粘贴功能
        editMenu_paste.addActionListener(e -> textArea.paste());
        // 撤销功能
        UndoManager undoManager = new UndoManager();
        textArea.getDocument().addUndoableEditListener(e -> undoManager.addEdit(e.getEdit()));
        editMenu_undo.addActionListener(e -> {
            if (undoManager.canUndo()) {
                undoManager.undo();
            }
        });
        // 重做功能
        editMenu_redo.addActionListener(e -> {
            if (undoManager.canRedo()) {
                undoManager.redo();
            }
        });
    }

    // 文件打开和保存方法
    private void file_OpenAndSave(String action, JLabel label1) {
        if ("open".equals(action)) {
            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            int result = chooser.showOpenDialog(null);
            if (result == JFileChooser.APPROVE_OPTION) {
                file = chooser.getSelectedFile();
                // 读取文件内容并显示在文本区域
                try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                    StringBuilder content = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        content.append(line).append("\n");
                    }
                    textArea.setText(content.toString());
                    // 更新标签显示当前打开的文件名
                    label1.setText("现在打开的文件：" + file.getName());
                    //启用代码保存
                    button_save.setEnabled(true);
                    fileMenu_save.setEnabled(true);
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(PagePanel, "文件读取错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                }
            }
        } else if ("save".equals(action)) {
            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            // 如果已经打开了文件，设置默认保存文件名为原文件名+“存档”
            if (file != null) {
                String originalName = file.getName();
                int lastDotIndex = originalName.lastIndexOf('.');
                if (lastDotIndex > 0) {
                    String nameWithoutExtension = originalName.substring(0, lastDotIndex);
                    String extension = originalName.substring(lastDotIndex);
                    chooser.setSelectedFile(new File(nameWithoutExtension + "-存档" + extension));
                } else {
                    chooser.setSelectedFile(new File(originalName + "-存档"));
                }
            }
            chooser.setDialogTitle("保存代码文件"); // 设置保存文件对话框标题
            int result = chooser.showSaveDialog(null);
            if (result == JFileChooser.APPROVE_OPTION) {
                File saveFile = chooser.getSelectedFile();
                try (java.io.FileWriter writer = new java.io.FileWriter(saveFile)) {
                    writer.write(textArea.getText());
                    JOptionPane.showMessageDialog(PagePanel, "文件保存成功！", "提示", JOptionPane.INFORMATION_MESSAGE);
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(PagePanel, "文件保存错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    //关闭文件的方法
    private void closeFile() {
        int result = JOptionPane.showConfirmDialog(PagePanel, "是否关闭当前文件以及清空显示内容？", "确认关闭", JOptionPane.YES_NO_OPTION);
        if (result == JOptionPane.YES_OPTION) {
            file = null;
            textArea.setText("");
            tokenTextArea.setText("");
            errorTextArea.setText("");
            fileMenu_saveToken.setEnabled(false);
            button_saveToken.setEnabled(false);
            button_save.setEnabled(false);
            fileMenu_save.setEnabled(false);
        }
    }
    // 保存Token序列到文本
    private void saveTokenSequence() {
        // 检查是否已进行词法分析
        String tokenText = tokenTextArea.getText();
        if (tokenText == null || tokenText.trim().isEmpty()) {
            JOptionPane.showMessageDialog(PagePanel, "请先进行词法分析再保存Token序列！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }

        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

        // 设置默认文件名
        if (file != null) {
            String originalName = file.getName();
            int lastDotIndex = originalName.lastIndexOf('.');
            if (lastDotIndex > 0) {
                String nameWithoutExtension = originalName.substring(0, lastDotIndex);
                chooser.setSelectedFile(new File(nameWithoutExtension + "token词法分析序列结果.txt"));
            } else {
                chooser.setSelectedFile(new File(originalName + "token词法分析序列结果.txt"));
            }
        } else {
            chooser.setSelectedFile(new File("token词法分析序列结果.txt"));
        }

        chooser.setDialogTitle("保存Token序列"); // 设置保存Token序列对话框标题
        int result = chooser.showSaveDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
            File saveFile = chooser.getSelectedFile();
            try (java.io.FileWriter writer = new java.io.FileWriter(saveFile)) {
                writer.write(tokenTextArea.getText());
                // 同时保存右下角的错误信息
                writer.write("\n\n" + errorTextArea.getText());
                JOptionPane.showMessageDialog(PagePanel, "Token序列保存成功！", "提示", JOptionPane.INFORMATION_MESSAGE);
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(PagePanel, "Token序列保存错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // 词法分析方法
    private void performLexicalAnalysis() {
        String codeText = textArea.getText();
        if (codeText == null || codeText.trim().isEmpty()) {
            JOptionPane.showMessageDialog(PagePanel, "左侧文本框中没有代码，请输入代码后再进行词法分析！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        StringBuilder tokenResult = new StringBuilder();
        tokenResult.append("词法分析结果: [序列序号] [词法单元] [代码词元]\n");
        tokenResult.append("--------------------\n");

        // 统计数量
        int errorCount = 0;
        int nonTokenCount = 0;
        StringBuilder formattedResult = new StringBuilder();
        int index = 1;
        int i = 0;
        while (i < codeText.length()) {
            char ch = codeText.charAt(i);
            // 跳过空白字符
            if (Character.isWhitespace(ch)) {
                i++;
                continue;
            }

            // 处理关键字和标识符 if、else、id
            if (Character.isLetter(ch)) {
                int start = i;
                while (i < codeText.length() && (Character.isLetterOrDigit(codeText.charAt(i)))) {
                    i++;
                }
                String word = codeText.substring(start, i);

                if ("if".equals(word)) {
                    tokenResult.append(String.format("%d\t%s\t%s\n", index++, "if", word));
                    formattedResult.append(String.format("<%s,%s> ", "if", word));
                } else if ("else".equals(word)) {
                    tokenResult.append(String.format("%d\t%s\t%s\n", index++, "else", word));
                    formattedResult.append(String.format("<%s,%s> ", "else", word));
                } else {
                    tokenResult.append(String.format("%d\t%s\t%s\n", index++, "id", word));
                    formattedResult.append(String.format("<%s,%d> ", "id", index-1));
                }
                continue;
            }

            // 处理数字number
            if (Character.isDigit(ch)) {
                int start = i;
                boolean hasDot = false;
                while (i < codeText.length() && (Character.isDigit(codeText.charAt(i)) ||
                        (codeText.charAt(i) == '.' && !hasDot))) {
                    if (codeText.charAt(i) == '.') {
                        hasDot = true;
                    }
                    i++;
                }
                String number = codeText.substring(start, i);
                tokenResult.append(String.format("%d\t%s\t%s\n", index++, "number", number));
                formattedResult.append(String.format("<%s,%d> ", "number", index-1));
                continue;
            }

            // 处理字符串 literal
            if (ch == '"') {
                int start = i;
                do {
                    i++;
                } while (i < codeText.length() && codeText.charAt(i) != '"');
                if (i < codeText.length()) {
                    i++;
                    String literal = codeText.substring(start + 1, i - 1);
                    tokenResult.append(String.format("%d\t%s\t%s\n", index++, "literal", literal));
                    formattedResult.append(String.format("<%s,%s> ", "literal", literal));
                } else {
                    tokenResult.append(String.format("\t%s\t%s\n", "非词元划分", "\""));
                    formattedResult.append(String.format("<%s,> ", "\""));
                    nonTokenCount++;
                    i = start + 1;
                }
                continue;
            }
            // 处理比较运算符comparison
            if (ch == '<' || ch == '>' || ch == '=' || ch == '!') {
                if (i + 1 < codeText.length()) {
                    char next = codeText.charAt(i + 1);
                    String op = "" + ch;
                    if (next == '=') {
                        op += "=";
                        i++;
                    }
                    i++;

                    if ("<>".equals(op) || ">=".equals(op) || "<=".equals(op) ||
                            "==".equals(op) || "!=".equals(op)) {
                        tokenResult.append(String.format("%d\t%s\t%s\n", index++, "comparison", op));
                        formattedResult.append(String.format("<%s,%s> ", "comparison", op));
                    } else {
                        tokenResult.append(String.format("\t%s\t%s\n", "非词元划分", op));
                        formattedResult.append(String.format("<%s,> ", op));
                        nonTokenCount++;
                    }
                } else {
                    i++;
                    if (ch == '<' || ch == '>') {
                        tokenResult.append(String.format("%d\t%s\t%s\n", index++, "comparison", ch));
                        formattedResult.append(String.format("<%s,%s> ", "comparison", ch));
                    } else {
                        tokenResult.append(String.format("\t%s\t%s\n", "非词元划分", ch));
                        formattedResult.append(String.format("<%s,> ", ch));
                        nonTokenCount++;
                    }
                }
                continue;
            }

            // 其他符号
            tokenResult.append(String.format("\t%s\t%s\n", "非词元划分", ch));
            formattedResult.append(String.format("<%s,> ", ch));
            nonTokenCount++;
            i++;
        }
        tokenTextArea.setText(tokenResult.toString());
        // 在右下角文本域显示错误统计和格式化结果
        String errorResult = "错误次数: " + errorCount + "\n" +
                "非标准词元个数: " + nonTokenCount + "\n\n" +
                "词法分析结果token序列:\n" +
                formattedResult;
        errorTextArea.setText(errorResult);

        // 启用保存Token序列功能
        fileMenu_saveToken.setEnabled(true);
        button_saveToken.setEnabled(true);
    }
}
